package br.com.hs.nfe.common.to;

import br.com.hs.nfe.common.anotation.DocumentTypeEnum;
import br.com.hs.nfe.common.anotation.Element;
import br.com.hs.nfe.common.anotation.Node;
import br.com.hs.nfe.common.anotation.TypeEnum;
import br.com.hs.nfe.common.validation.Validable;
import br.com.hs.nfe.common.enumeration.IndTotEnum;
import br.inf.portalfiscal.nfe.TCfop;
import br.inf.portalfiscal.nfe.TNFe;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * Classe de dados dos produtos e serviços da NF-e.
 * @author Ranlive Hrysyk
 */
@Node(id = "I", name = "Produto")
public class ProdutoTO extends BaseTO implements Validable {

    @Element(publicName = "Cód. Produto", type = TypeEnum.CARACTER, min = 1, max = 60)
    private String cProd;
    @Element(publicName = "Cód. EAN", type = TypeEnum.CARACTER, max = 14, formart = "[0-9]{0}|[0-9]{8}|[0-9]{12,14}")
    private String cEAN;
    @Element(publicName = "Descrição do Produto", type = TypeEnum.CARACTER, min = 1, max = 120)
    private String xProd;
    @Element(elementName = "NCM", publicName = "Código NCM", type = TypeEnum.CARACTER, min = 2, max = 8, formart = "[0-9]{2}|[0][1-9][0-9]{6}|[1-9][0-9]{7}")
    private String ncm;
    @Element(elementName = "EXTIPI", publicName = "Código EX da TIPI", type = TypeEnum.CARACTER, min = 2, max = 3, required = false, formart = "[0-9]{2,3}")
    private String exTIPI;
    @Element(elementName = "CFOP", publicName = "CFOP", type = TypeEnum.ENUM, min = 4, max = 4, classType = TCfop.Enum.class, document= DocumentTypeEnum.CFOP)
    private String cfop;
    @Element(publicName = "Und. Comercial", type = TypeEnum.CARACTER, min = 1, max = 6)
    private String uCom;
    @Element(publicName = "Qtde. Comercial", type = TypeEnum.DECIMAL, decimalCount = 4)
    private BigDecimal qCom;
    @Element(publicName = "Valor Unitário de Comercialização", type = TypeEnum.DECIMAL, decimalCount = 10)
    private BigDecimal vUnCom;
    @Element(publicName = "Valor Total dos Produtos", type = TypeEnum.DECIMAL, decimalCount = 2)
    private BigDecimal vProd;
    @Element(publicName = "Cód. EAN da Unidade Tributável", type = TypeEnum.CARACTER, max = 14, formart = "[0-9]{0}|[0-9]{8}|[0-9]{12,14}")
    private String cEANTrib;
    @Element(publicName = "Und. Tributável", type = TypeEnum.CARACTER, min = 1, max = 6)
    private String uTrib;
    @Element(publicName = "Qtde. Tributável", type = TypeEnum.DECIMAL, decimalCount = 4)
    private BigDecimal qTrib;
    @Element(publicName = "Valor Unitário de Tributação", type = TypeEnum.DECIMAL, decimalCount = 10)
    private BigDecimal vUnTrib;
    @Element(publicName = "Valor Total do Frete", type = TypeEnum.DECIMAL, decimalCount = 2, required = false)
    private BigDecimal vFrete;
    @Element(publicName = "Valor Total do Seguro", type = TypeEnum.DECIMAL, decimalCount = 2, required = false)
    private BigDecimal vSeg;
    @Element(publicName = "Valor do Desconto", type = TypeEnum.DECIMAL, decimalCount = 2, required = false)
    private BigDecimal vDesc;
    @Element(publicName = "Outras Despesas Acessórias", type = TypeEnum.DECIMAL, decimalCount = 2, required = false)
    private BigDecimal vOutro;
    @Element(publicName = "Compõe Total", type = TypeEnum.ENUM, classType = TNFe.InfNFe.Det.Prod.IndTot.Enum.class)
    private IndTotEnum indTot;
    @Element(elementName = "medArray", publicName = "Lista de Medicamentos", type = TypeEnum.ARRAY, required = false, classType = TNFe.InfNFe.Det.Prod.Med.class)
    private List<MedicamentoTO> meds;

    /**
     * Código do Produto ou Serviço
     */
    public String getCProd() {
        return cProd;
    }

    /**
     * Informar o código do produto ou serviço.
     * <p><i>Prencher com CFOP, case se trate de itens não relacionados com mercadorias/produtos e que o 
     * contribuinte não possua codificação própria. Formato: "CFOP9999"</i></p>
     * @param cProd Código do Produto ou Serviço
     */
    public void setCProd(String cProd) {
        this.cProd = cProd;
    }

    /**
     * Código EAN.
     */
    public String getCEAN() {
        return cEAN;
    }

    /**
     * Informar o GTIN (Global Trade Item Number) do produto, antigo código EAN ou código de barras.
     * <p><i>Preencher com o código GTIN-8, GTIN-12, GTIN-13 ou GTIN-14 (antigos códigos EAN, UPC e DUN-14).</i></p>
     * @param cEAN Código EAN
     */
    public void setCEAN(String cEAN) {
        this.cEAN = cEAN;
    }

    /**
     * Descrição do Produto ou Serviço.
     */
    public String getXProd() {
        return xProd;
    }

    /**
     * Informar a descrição do produto ou serviço.
     * @param xProd Descrição do Produto ou Serviço.
     */
    public void setXProd(String xProd) {
        this.xProd = xProd;
    }

    /**
     * Código NCM.
     */
    public String getNCM() {
        return ncm;
    }

    /**
     * Informar o código NCM com 8 dígitos ou 2 dígitos (gênero).
     * <p><i>Código NCM (8 posições), informar o gênero (posição do capítulo do NCM) quando a operação
     * não for de comércio exterior (importação/exportação) ou o produto não seja tributado pelo IPI.<br>
     * Em caso de serviço, informar o código 99.</i></p>
     * @param ncm Código NCM
     */
    public void setNCM(String ncm) {
        this.ncm = ncm;
    }

    /**
     * Código EX da TIPI.
     */
    public String getEXTIPI() {
        return exTIPI;
    }

    /**
     * Informar de acordo com o código EX da TIPI. Em caso de serviço, não informar o campo.
     * @param exTIPI Código EX da TIPI
     */
    public void setEXTIPI(String exTIPI) {
        this.exTIPI = exTIPI;
    }

    /**
     * Código Fiscal de Operações e Prestações
     */
    public String getCFOP() {
        return cfop;
    }

    /**
     * Informar o código fiscal de operações e prestações.
     * @param cfop Código Fiscal de Operações e Prestações
     */
    public void setCFOP(String cfop) {
        this.cfop = cfop;
    }

    /**
     * Unidade Comercial.
     */
    public String getUCom() {
        return uCom;
    }

    /**
     * Informar a unidade de comercialização do produto.
     * @param uCom Unidade Comercial
     */
    public void setUCom(String uCom) {
        this.uCom = uCom;
    }

    /**
     * Quantidade Comercial.
     */
    public BigDecimal getQCom() {
        return qCom;
    }

    /**
     * Informar a quantidade de comercialização do produto.
     * @param qCom Quantidade Comercial
     */
    public void setQCom(BigDecimal qCom) {
        this.qCom = qCom;
    }

    /**
     * Valor Unitário de Comercialização.
     */
    public BigDecimal getVUnCom() {
        return vUnCom;
    }

    /**
     * Informar o valor unitário de comercialização do produto.
     * <p><i>Para efeitos de cálculo, o valor unitário será obtido pela divisão do valor do produto pela quantidade comercial. 
     * @param vUnCom Valor Unitário de Comercialização.
     */
    public void setVUnCom(BigDecimal vUnCom) {
        this.vUnCom = vUnCom;
    }

    /**
     * @return the vProd
     */
    public BigDecimal getVProd() {
        return vProd;
    }

    /**
     * @param vProd the vProd to set
     */
    public void setVProd(BigDecimal vProd) {
        this.vProd = vProd;
    }

    /**
     * Código EANTrib.
     */
    public String getCEANTrib() {
        return cEANTrib;
    }

    /**
     * Informar o GTIN (Global Trade Item Number) da unidade tributável, antigo código EAN ou código de barras.
     * <p><i>Preencher com o código GTIN-8, GTIN-12, GTIN-13 ou GTIN-14 (antigos códigos EAN, UPC e DUN-14) da 
     * unidade tributável do produto.</i></p>
     * @param cEANTrib Código EANTrib
     */
    public void setCEANTrib(String cEANTrib) {
        this.cEANTrib = cEANTrib;
    }

    /**
     * Unidade Tributável.
     */
    public String getUTrib() {
        return uTrib;
    }

    /**
     * Informar a unidade tributável.
     * @param uTrib Unidade Tributável
     */
    public void setUTrib(String uTrib) {
        this.uTrib = uTrib;
    }

    /**
     * Quantidade Tributável.
     */
    public BigDecimal getQTrib() {
        return qTrib;
    }

    /**
     * Informar a quantidade tributável.
     * @param qTrib Quantidade Tributável
     */
    public void setQTrib(BigDecimal qTrib) {
        this.qTrib = qTrib;
    }

    /**
     * Valor Unitário de Tributação
     */
    public BigDecimal getVUnTrib() {
        return vUnTrib;
    }

    /**
     * Informar o valor unitário de tributação.
     * @param vUnTrib Valor Unitário de Tributação
     */
    public void setVUnTrib(BigDecimal vUnTrib) {
        this.vUnTrib = vUnTrib;
    }

    /**
     * Valor do Frete.
     */
    public BigDecimal getVFrete() {
        return vFrete;
    }

    /**
     * Informar o valor do frete.
     * @param vFrete Valor do Frete
     */
    public void setVFrete(BigDecimal vFrete) {
        this.vFrete = vFrete;
    }

    /**
     * Valor do Seguro.
     */
    public BigDecimal getVSeg() {
        return vSeg;
    }

    /**
     * Informar o valor do seguro.
     * @param vSeg Valor do Seguro
     */
    public void setVSeg(BigDecimal vSeg) {
        this.vSeg = vSeg;
    }

    /**
     * Valor do Desconto.
     */
    public BigDecimal getVDesc() {
        return vDesc;
    }

    /**
     * Informar os valores de descontos e abatimentos que tem reflexo no valor da NF.
     * @param vDesc Valor do Desconto
     */
    public void setVDesc(BigDecimal vDesc) {
        this.vDesc = vDesc;
    }

    /**
     * Outras despesas acessórias.
     */
    public BigDecimal getVOutro() {
        return vOutro;
    }

    /**
     * Inforar os calores do item que devem compor o valor da NF, mas não tenam campo de total correspondente no grupo ICMSTot.
     * @param vOutro Outras despesas acessórias
     */
    public void setVOutro(BigDecimal vOutro) {
        this.vOutro = vOutro;
    }

    /**
     * Compõe Total NF-e.
     */
    public String getIndTot() {
        if (indTot != null) {
            return indTot.getCodigo();
        }
        return null;
    }

    /**
     * Compõe Total NF-e.
     */
    public IndTotEnum getIndTotEnum() {
        return indTot;
    }

    /**
     * Informar se o valor do produto (vProd) entra no valor total da NF-e.
     * <p>Este campo deverá obrigatoriamente ser preenchido com:
     * <br>0 - O valor do item (vProd) não compõe o valor total da NF-e;
     * <br>1 - O valor do item (vProd) compõe o valor total da NF-e.
     * </p>
     * @param indTot Compõe Total NF-e
     */
    public void setIndTot(String indTot) {
        this.indTot = IndTotEnum.getEnumByCodigo(indTot);
    }

    /**
     * Informar se o valor do produto (vProd) entra no valor total da NF-e.
     * @param indTot Compõe Total NF-e
     */
    public void setIndTotEnum(IndTotEnum indTot) {
        this.indTot = indTot;
    }

    /**
     * Lista de detalhamento de medicamentos específicos.
     */
    public List<MedicamentoTO> getMedList() {
        return meds;
    }

    /**
     * Array de detalhamento de medicamentos específicos.
     */
    public MedicamentoTO[] getMedArray() {
        if (meds != null) {
            MedicamentoTO[] medicamentoTOs = new MedicamentoTO[meds.size()];
            for (int i = 0; i < meds.size(); i++) {
                medicamentoTOs[i] = meds.get(i);
            }
            return medicamentoTOs;
        }
        return null;
    }

    /**
     * Informar a lista de detalhamento de medicamentos específicos ou de matérias-primas farmacêuticas.
     * @param meds Lista de detalhamento de medicamentos específicos.
     */
    public void setMedList(List<MedicamentoTO> meds) {
        this.meds = meds;
    }

    public void setMedArray(MedicamentoTO[] meds) {
        if (meds != null) {
            this.meds = new ArrayList<MedicamentoTO>();
            this.meds.addAll(Arrays.asList(meds));
            return;
        }
        this.meds = null;
    }
}
